package com.yjzx.factory;

import com.yjzx.bean.ClassInfo;
import com.yjzx.bean.MethodUpdate;
import com.yjzx.bean.UpdateCtClass;
import com.yjzx.config.YamlConfig;
import com.yjzx.util.FileUtil;
import com.yjzx.util.SystemUtil;
import javassist.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;

/**
 * @author yjzx
 * @date 2023/10/20
 * @description
 */
@Component
public class PropertiesFactory {
    @Autowired
    private YamlConfig config;

    public boolean execute() {
        File file;
        String printPath = config.getPrintPath();
        if (printPath != null && !"".equals(printPath.trim())) {
            file = new File(config.getPrintPath());
            if (!file.isAbsolute()) {
                file = new File(System.getProperty("user.dir") + File.separator + printPath);
            } else {
                file.getParentFile().mkdirs();
            }
        } else {
            file = new File(System.getProperty("user.dir") + File.separator);
        }
        String jarPath = toJarPath(config.getJarName(), config.getJarPath());
        try {
            ClassPool pool = ClassPool.getDefault();
            // 此处改为你实际的的 .jar 的路径
            try {
                pool.insertClassPath(jarPath);
            } catch (NotFoundException e) {
                throw new RuntimeException("输入准确的jar路径，当前路径为：" + jarPath);
            }
            File finalFile = file;
            config.getClassInfo().stream()
                    .map(x -> updateClass(pool, x)).forEach(x -> {
                                try {
                                    x.getCtClass().writeFile(finalFile.getPath());
                                    String className = x.getCtClass().getName();
                                    String classPathName = className.replace(".", File.separator) + ".class";
                                    //复制jar包
                                    FileUtil.copyFileUsingFileChannels(new File(jarPath), new File(finalFile.getPath() + File.separator + config.getJarName()));
                                    //复制class文件
                                    File newClass = new File(finalFile.getPath() + File.separator + className.substring(className.lastIndexOf(".") + 1) + ".class");
                                    FileUtil.copyFileUsingFileChannels(new File(finalFile.getPath() + File.separator + classPathName), newClass);
                                    //执行的修改class的命令
                                    updateJar(finalFile, classPathName);
                                    String[] split = className.split("\\.");
                                    File delFile = new File(finalFile.getPath() + File.separator + split[0]);
                                    FileUtil.delFolder(newClass);
                                    FileUtil.delFolder(delFile);
                                } catch (CannotCompileException | IOException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                    );

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return true;
    }


    /**
     * 更新class文件
     *
     * @param pool
     * @param classInfo
     * @return
     */
    private UpdateCtClass updateClass(ClassPool pool, ClassInfo classInfo) {
        String classPath = null;
        CtClass ctClass = null;
        try {
            classPath = classInfo.getClassPath() + "." + classInfo.getClassName();
            ctClass = pool.get(classPath);
            for (MethodUpdate method : classInfo.getMethods()) {
                CtMethod ctMethod;
                List<String> params = method.getParams();
                if (params == null || params.size() == 0) {
                    ctMethod = ctClass.getDeclaredMethod(method.getName());
                } else {
                    CtClass[] classes = new CtClass[params.size()];

                    for (int i = 0; i < params.size(); i++) {
                        classes[i] = pool.get(params.get(i));
                    }
                    ctMethod = ctClass.getDeclaredMethod(method.getName(), classes);
                }
                if (ctMethod != null) {
                    ctMethod.setBody(method.getBody());
                } else {
                    //添加方法
                    String returnType = method.getReturnType();
                    CtClass[] classes = new CtClass[params == null ? 0 : params.size()];
                    for (int i = 0; i < params.size(); i++) {
                        classes[i] = pool.get(params.get(i));
                    }
                    ctClass.addMethod(new CtMethod(returnType == null ? CtClass.voidType : pool.getCtClass(returnType), method.getName(), classes, ctClass));
                }

            }
        } catch (NotFoundException | CannotCompileException e) {
            throw new RuntimeException(e);
        }


        return new UpdateCtClass(ctClass, classPath);

    }

    /**
     * 更新jar
     * @param finalFile jar路径名称
     * @param classPathName class在jar的路径名称
     * @throws IOException
     */
    private void updateJar(File finalFile, String classPathName) throws IOException {
        String command = "jar -uvf " + finalFile.getPath() + File.separator + config.getJarName() + " " + classPathName;
        SystemUtil.extracted(finalFile, command);
    }



    /**
     * 获取jar路径
     *
     * @param jarName
     * @param jarPath
     * @return
     */
    public static String toJarPath(String jarName, String jarPath) {

        File file ;
        if (jarName != null && !"".equals(jarName.trim())) {
            int index = jarName.lastIndexOf(".jar");
            String substring = jarName.substring(index == -1 ? 0 : index);
            if (".jar".equals(substring)) {
                if (jarPath == null || "".equals(jarPath.trim())) {
                    file = new File(System.getProperty("user.dir") + File.separator + jarName);
                } else {
                    file = new File(jarPath + File.separator + jarName);
                }
                if (!file.isDirectory()) {
                    return file.getPath();
                }
            }
        }
        throw new RuntimeException("jar路径不存在，请输入正确路径或将文件放入项目根目录");
    }

}
